/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package job;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.Connection;
import net.Packet;
import net.Utility;

/**
 *
 * @author Andrea
 */
public class WorkConnection extends Connection implements Worker {

    private boolean ready;
    private ProtocolManager manager;
    
    public WorkConnection(Socket socket) throws IOException {
        super(socket);
    }

    @Override
    public boolean isReady() {
        return ready;
    }

    public void setReady(boolean isReady) {
        this.ready = isReady;
    }

    @Override
    public void logToManager(JobsManager jm) {
        addObserver(jm);
    }

    @Override
    public void doWork(Work w) throws IOException {
        if (ready) {
            sendPacket(Packet.DataType.JOB, Utility.serialize(w));
        }
    }

    @Override
    public void start() throws IOException {
        manager = new ProtocolManager("protocol manager");
        
        manager.start();
    }

    @Override
    public void close() throws IOException {
        super.close();
        
        manager.done = true;
    }
    
    

    protected class ProtocolManager extends Thread{

        private final InputStream in;
        private final OutputStream out;

        protected volatile boolean done;

        public ProtocolManager(String name) throws IOException {
            super(name);

            in = WorkConnection.this.socket.getInputStream();
            out = WorkConnection.this.socket.getOutputStream();

            done = false;
        }

        @Override
        @SuppressWarnings("CallToThreadRun")
        public void run() {
            handshake();

            //job phase
            while (!done) {
                Packet p;
                try {
                    p = pb.getNext();
                } catch (IOException ex) {
                    Logger.getLogger(Connection.class.getName()).log(Level.SEVERE, "End when trying to read the response from the client", ex);
                    done = true;
                    break;
                }

                switch (p.getDataCode()) {
                    case PASSWORD:
                        String pwd = new String(p.getData());

                        user.setPassword(pwd);

                        break;
                    case SPECIFICS:
                        String spec = new String(p.getData());

                        user.setSpecifics(spec);

                        break;
                    case JOB:
                        //set client ready to get a work and register it to the work manager
                        ready = true;
                        
                        JobsManager.notifyReady(WorkConnection.this);
                        break;
                    case JOB_LIB:
                        String className = new String(p.getData());

                        try {
                            Class c = Class.forName(className);

                            File jar = JobsManager.getJarLocation(c);

                            byte file[];
                            try {
                                file = Files.readAllBytes(Paths.get(jar.getPath()));
                            } catch (IOException ex) {
                                //an error occourred while reading the file
                                
                                break;
                            }

                            try {
                                sendPacket(Packet.DataType.JOB_LIB, file);
                            } catch (IOException ex) {
                                Logger.getLogger(WorkConnection.class.getName()).log(Level.SEVERE, null, ex);
                            }

                        } catch (ClassNotFoundException ex) {
                            try {
                                sendPacket(Packet.DataType.EXCEPTION, "class not found".getBytes());
                            } catch (IOException ex1) {
                                Logger.getLogger(WorkConnection.class.getName()).log(Level.SEVERE, null, ex1);
                            }
                        }

                        break;
                }
            }

            //notify the end of the connection to the connections manager
            notifyObservers();
        }

    }
}
